package MyHelper;

import java.util.ArrayList;
import java.io.File;


public class GeneInformation {
	private String hostname="genome-mysql.cse.ucsc.edu";
	private String db="hg19";
	//private String user = "genome";
	//private String password = "";
	
	private int extendedRange = 100000;
	private int numberOfNeighbors = 5;
	
	//private String query="";
	private String newline ="\n";
	private int minimum_length = 10;
	
	/**
	 * take the name2 of genes in input file and put those name2 in output file
	 * 
	 * @param inFile name of input file (contains genes extracted from refGene table (hg19)
	 * @param outFile name of output file
	 */
	public void refGeneToName2(String inFile, String outFile){
		int[] cols = {10};
		getColumnsOfFile(inFile, outFile, cols);
	}
	/**
	 * get 1 column of input file and put it in output file
	 * 
	 * @param inFile
	 * @param outFile
	 * @param colIndex
	 */
	public void get1Col(String inFile, String outFile, int colIndex){
		int[] cols = {colIndex};
		getColumnsOfFile(inFile, outFile, cols);
	}
	/**
	 * Get selected columns from input file and put them into output file.
	 * Columns separated by tabs. This method can be replaced by the same
	 * static method of MyFile class
	 * 
	 * @param inFile source file
	 * @param outFile contains selected columns
	 * @param cols contains index of selected columns
	 */
	public void getColumnsOfFile(String inFile, String outFile, int[] cols){
		ArrayList<String> inGenes = MyFile.readFileToArrayListOfString(inFile);
		StringBuffer result = new StringBuffer();
		for(String line:inGenes){
			String[] geneCol = line.split("\t");
			if (geneCol[1].length()>1){
				for (int i=0;i<cols.length;i++){
					if (geneCol[cols[i]].length()>1){
						result.append(geneCol[cols[i]]+"\t");
					}
				}
				result.append(newline);
			}
		}
		MyFile.writeToFile(outFile, result);
	}
	
	/**
	 * This method takes file from input directory, read genes information and then
	 * try to get the corresponding genes from refGene table.
	 * 
	 * @param inDir contains file and each file contains gene information from knownGene table
	 * @param outDir contains file and each file contains gene information from refGene table
	 */
	public void hg19KnownGene2ProtetinID_D2D(String inDir, String outDir){
		File sourceDir = new File (inDir);
		if (sourceDir.isDirectory()){
			for(String sourceFName:sourceDir.list()){
				System.out.println("Processing "+sourceFName);
				hg19KnownGene2ProtetinID_F2F(inDir+"/"+sourceFName, outDir+"/"+sourceFName);
			}
		}
		
	}
	
	/**
	 * When we start with a fasta-format file from ChEMBL we "first" get the
	 * information of genes from knownGene table, but LocusVu find the neighbors
	 * by using refGene table. so we may need this method to "convert" a gene to
	 * corresponding gene but it have some problems. First: we may not find the
	 * corresponding file. Second: for each file in knownGene we can file multiple
	 * gene at the same position from refGene table
	 * 
	 * @param inFile Name of the file that contains genes from knownGene table
	 * @param outFile Name of the file that contains genes from refGene table
	 */
	public void hg19KnownGene2ProtetinID_F2F(String inFile, String outFile){
		ArrayList<String> inGenes = MyFile.readFileToArrayListOfString(inFile);
		StringBuffer result = new StringBuffer();
		StringBuffer result2 = new StringBuffer();
		
		for(String gene:inGenes){
			if(gene.indexOf("chr")>0){
				String[] geneCol = gene.split("\t");
				if(geneCol[1].length()>2&&geneCol[8].length()>2){
					result.append(geneCol[8]+newline);
					result2.append(geneCol[1]+"\t"+ geneCol[8]+newline);
				}
			}
			
		}
		MyFile.writeToFile(outFile.replace(".txt", "_protID.txt"), result);
		MyFile.writeToFile(outFile.replace(".txt", "_protID_genePos.txt"), result2);
	}
	
	/**
	 * After finding neighbors for each genes, we have a directory contains many files,
	 * each file contains gene and it's neighbors. this method will try to get protein
	 * for each gene in every files
	 * 
	 * @param geneDir contains files, each file contains gene and it's neighbors 
	 * @param protDir contains files, each file contains corresponding proteins of genes in input 
	 */
	public void geneDirToProteinDir(String geneDir, String protDir){
		//scan all files in geneDir, get protein information for each files
		//put protein file in protDir
		File sourceDir = new File (geneDir);
		if (sourceDir.isDirectory()){
			for(String sourceFName:sourceDir.list()){
				System.out.println("Processing "+sourceFName);
				geneListToProteinList(geneDir+"/"+sourceFName, protDir+"/"+sourceFName);
			}
		}
		
	}
	
	public void geneListToProteinList(String inFile, String outFile){
		ArrayList<String> geneList = MyFile.readFileToArrayListOfString(inFile);
		StringBuffer result = new StringBuffer();
		for (String gene:geneList){
			result.append(geneToProtein(gene, "knownGene"));
		}
		MyFile.writeToFile(outFile, result);
	}
	
	/**
	 * Phuong thuc nay khong tot cho lam vi ten phuong thuc thuc su khong phan anh dung 
	 * nhung gi ma phuong thuc nay thuc hien. phuong thuc nay thuc ra van la nhan thong
	 * tin ve gene sau do phan tich tim vi tri cua gene. cuoi cung la tim trong bang
	 * source table cac gene co cung vi tri.
	 * 
	 * @param gene input gene that contains gene position
	 * @param sourceTable= the table where we find neighbors gene
	 * 
	 * @return a String contains gene(s) that are neighbors of input gene
	 */
	public String geneToProtein(String gene, String sourceTable){
		String result = new String();
		String[] geneCol = gene.split("\t");
		int genePosCol = -1, chrIndex = -1, dotIndex=-1,subIndex=-1;
		for (int i = 0;i<geneCol.length;i++){
			chrIndex = geneCol[i].indexOf("chr");
			dotIndex = geneCol[i].indexOf(":");
			subIndex = geneCol[i].indexOf("-");
			if(chrIndex>=0 && dotIndex>0 && subIndex>0){
				genePosCol = i;
			}
		}
		if(genePosCol>-1){
			chrIndex = geneCol[genePosCol].indexOf("chr");
			dotIndex = geneCol[genePosCol].indexOf(":");
			subIndex = geneCol[genePosCol].indexOf("-");
			
			String chr = geneCol[genePosCol].substring(chrIndex,dotIndex);
			String txStart = geneCol[genePosCol].substring(dotIndex+1,subIndex);
			String txEnd = geneCol[genePosCol].substring(subIndex+1);
			//String outName = chr+"_"+txStart+"_"+txEnd + "_proteins.txt";
			String queri = "SELECT * FROM "+sourceTable+" WHERE chrom = \'"
					+ chr
					+ "\' AND txEnd = "
					+ txEnd
					+ " AND txStart = "
					+ txStart;
			MYSQLDatabase ucscDB = new MYSQLDatabase(hostname,db);
			result = new String(ucscDB.queryToStringBuffer(queri));
		}
		return result;
	}
	
	/**
	 * This method reads a list of genes from input file, then it try to get
	 * neighbors for each gene in list. put each gene and its neighbors in 1
	 * file and put all output files in output directory.
	 * 
	 * This method may needed to modified so that we can control each output file
	 * 
	 * @param inputListFile = Name of file that contains list of genes
	 * @param sourceTable = the table from which we get neighbors for genes
	 * @param outDir = directory stores all output files
	 * 
	 * @return void
	 */
	public void getNeighborsOfList(String inputListFile, String sourceTable, String outDir){
		ArrayList<String> geneList = MyFile.readFileToArrayListOfString(inputListFile);
		
		for(String gene:geneList){
			String[] geneCol = gene.split("\t");
			int genePosCol = -1, chrIndex = -1, dotIndex=-1,subIndex=-1;
			for (int i = 0;i<geneCol.length;i++){
				chrIndex = geneCol[i].indexOf("chr");
				dotIndex = geneCol[i].indexOf(":");
				subIndex = geneCol[i].indexOf("-");
				if(chrIndex>=0 && dotIndex>0 && subIndex>0){
					genePosCol = i;
				}
			}
			
			if(genePosCol>-1){
				chrIndex = geneCol[genePosCol].indexOf("chr");
				dotIndex = geneCol[genePosCol].indexOf(":");
				subIndex = geneCol[genePosCol].indexOf("-");
				
				String chr = geneCol[genePosCol].substring(chrIndex,dotIndex);
				String txStart = geneCol[genePosCol].substring(dotIndex+1,subIndex);
				String txEnd = geneCol[genePosCol].substring(subIndex+1);
				String outName = chr+"_"+txStart+"_"+txEnd;
				
				if(sourceTable.equals("refGene"))
					outName += "_"+geneCol[12];
				if(sourceTable.equals("refGene"))
					outName += "_"+geneCol[10]+"_"+geneCol[11];
				
				outName+="_neighbors.txt";
				
				System.out.println("processing gene at "+chr+":"+txStart+"-"+txEnd);
				getNeighborsToFile(gene, sourceTable, outDir+"/"+outName);
			}
		}
		
	}
	/**
	 * This method first try to find out the position of gene from gene infor,
	 * then it try to find neighbors of this gene an write them to a file
	 * 
	 * @param geneInfo = gene that we want to find neighbors
	 * @param sourceTable = the table provides neighbors for input gene
	 * @param outFile = the name of the file contains neighbors of input gene
	 * 
	 * @return void
	 */
	public void getNeighborsToFile(String geneInfo, String sourceTable, String outFile){
		String[] geneCol = geneInfo.split("\t");
		int genePosCol = -1, chrIndex = -1, dotIndex=-1,subIndex=-1;
		for (int i = 0;i<geneCol.length;i++){
			chrIndex = geneCol[i].indexOf("chr");
			dotIndex = geneCol[i].indexOf(":");
			subIndex = geneCol[i].indexOf("-");
			if(chrIndex>=0 && dotIndex>0 && subIndex>0){
				genePosCol = i;
			}
		}
		
		if(genePosCol>-1){
			chrIndex = geneCol[genePosCol].indexOf("chr");
			dotIndex = geneCol[genePosCol].indexOf(":");
			subIndex = geneCol[genePosCol].indexOf("-");
			String chr = geneCol[genePosCol].substring(chrIndex,dotIndex);
			String txStart = geneCol[genePosCol].substring(dotIndex+1,subIndex);
			String txEnd = geneCol[genePosCol].substring(subIndex+1);
			
			String queryUpStream = "SELECT * FROM "+sourceTable+" WHERE chrom = \'"
					+ chr
					+ "\' AND txEnd BETWEEN "
					+ Integer.toString(Integer.parseInt(txStart)- this.extendedRange)
					+ " AND "
					+ txStart
					+ " ORDER BY txEnd DESC LIMIT "
					+ Integer.toString(this.numberOfNeighbors + 20);
			// downstream query
			String queryDownStream = "SELECT * FROM "+sourceTable+" WHERE chrom = \'"
					+ chr
					+ "\' AND txStart BETWEEN "
					+ txEnd
					+ " AND "
					+ Integer.toString(Integer.parseInt(txEnd)+ this.extendedRange)
					+ " ORDER BY txStart LIMIT "
					+ Integer.toString(this.numberOfNeighbors + 20);
			
			StringBuffer result = new StringBuffer();
			//sau nay doi sang server khac UCSC thi can username + pass luc day nho sua dong sau
			MYSQLDatabase ucscDB = new MYSQLDatabase(hostname,db);
			result.append(ucscDB.queryToStringBuffer(queryUpStream)+newline);
			result.append(geneInfo+newline);
			result.append(ucscDB.queryToStringBuffer(queryDownStream)+newline);
			
			MyFile.writeToFile(outFile, result);
			System.out.println("Check "+outFile+ " for the result of neighboring genes");
			
		}else{
			System.out.println("Cannot find a valid gene position in the input gene");
		}
	}
	
	//3 phuong thuc sau doc gene list tu file va "co gang" lay thong tin day du cua cac gene nay
	/**
	 * This method read a list of gene names from input file the, try to get other information 
	 * of every files in this list and put the result into an output file.
	 * This method still use file name2 so it can only use for human
	 * 
	 * @param inFile
	 * @param sourceTable
	 * 
	 * @return void 
	 */
	public void geneListToGeneInFile(String inFile, String outFile, String sourceTable){
		MyFile.writeToFile(outFile, geneListToGeneInStringBuffer(inFile, sourceTable));
	}
	
	/**
	 * This method read a list of gene names from input file the, try to get other information 
	 * of every files in this list. This method still use file name2 so it can only use for human
	 * 
	 * @param inFile
	 * @param sourceTable
	 * 
	 * @return an StringBuffer 
	 */
	public StringBuffer geneListToGeneInStringBuffer(String inFile, String sourceTable){
		MYSQLDatabase ucscDB = new MYSQLDatabase(hostname,db);
		
		//read input file to get the gene list
		ArrayList<String> geneList = MyFile.readFileToArrayListOfString(inFile);
		
		StringBuffer result= new StringBuffer();
		for(String gene:geneList){
			if(gene.length()>1){
				String queri = "select * from " + sourceTable +" where name2 = \'"+gene+"\'";
				String tmp = ucscDB.queryToStringBuffer(queri)+newline;
				if (tmp.length()>minimum_length)
					result.append(tmp);
			}
		}
		
		return result;
	}
	
	/**
	 * This method read a list of gene names from input file the, try to get other information 
	 * of every files in this list. This method still use file name2 so it can only use for human
	 * 
	 * @param inFile
	 * @param sourceTable
	 * 
	 * @return an ArrayList<String> 
	 */
	public ArrayList<String> geneListToGeneInArrayList(String inFile, String sourceTable){
		MYSQLDatabase ucscDB = new MYSQLDatabase(hostname,db);
		
		//read input file to get the gene list
		ArrayList<String> geneList = MyFile.readFileToArrayListOfString(inFile);
		
		ArrayList<String> result= new ArrayList<String>();
		for(String gene:geneList){
			String queri = "select * from " + sourceTable +" where name2 = \'"+gene+"\'";
			for (String s:ucscDB.queryToArrayListString(queri))
				if(s.length()>12)//try to ignore empty line (12 is number of tab chars)
					result.add(s);
		}
				
		return result;
	}
	
	
	//3 phuong thuc sau convert 1 gene thanh thong tin day du cua gene lay tu bang sourceTable
	/**
	 * From Name of gene, try to get other information of gene from a source table.
	 * This method still use field name2, so it only for human 
	 * 
	 * @param geneName = the name of the gene that we want to get it's information from 
	 * source Table
	 * @param sourceTable provide information about genes
	 * @return a StringBuffer of found gene that have same name
	 */
	public StringBuffer geneNameToGeneInStringBuffer(String geneName, String sourceTable){
		MYSQLDatabase ucscDB = new MYSQLDatabase(hostname,db);
		String queri = "select * from " + sourceTable +" where name2 = \'"+geneName+"\'";
		
		return ucscDB.queryToStringBuffer(queri);
	}
	
	/**
	 * From Name of gene, try to get other information of gene from a source table.
	 * This method still use field name2, so it only for human
	 * 
	 * @param geneName = the name of the gene that we want to get it's information from 
	 * source Table
	 * @param sourceTable provide information about genes
	 * 
	 * @return an String[]
	 */
	public String[] geneNameToGeneInStringArray(String geneName, String sourceTable){
		MYSQLDatabase ucscDB = new MYSQLDatabase(hostname,db);
		String queri = "select * from " + sourceTable +" where name2 = \'"+geneName+"\'";
		
		return ucscDB.queryToStringArray(queri);
	}
	
	/**
	 * From Name of gene, try to get other information of gene from a source table.
	 * This method still use field name2, so it only for human
	 * 
	 * @param geneName = the name of the gene that we want to get it's information from 
	 * source Table
	 * @param sourceTable provide information about genes
	 * 
	 * @return an ArrayList of found gene that have same name
	 */
	public ArrayList<String> geneNameToGeneInArrayList(String geneName, String sourceTable){
		MYSQLDatabase ucscDB = new MYSQLDatabase(hostname,db);
		String queri = "select * from " + sourceTable +" where name2 = \'"+geneName+"\'";
		
		return ucscDB.queryToArrayListString(queri);
	}
	
}
